package com.suray.wcs.web.system.controller;

import com.suray.basic.wcs.path.core.Node;
import com.suray.basic.wcs.plc.core.Plc;
import com.suray.basic.wcs.plc.enums.Location;
import com.suray.basic.wcs.plc.enums.PlcDeviceType;
import com.suray.basic.wcs.plc.oper.impl.PlcOperImpl;
import com.suray.basic.wcs.plc.pojo.oper.StationOper;
import com.suray.basic.wcs.plc.pojo.device.Scanner;
import com.suray.commin.annotation.Log;
import com.suray.commin.core.controller.BaseController;
import com.suray.commin.core.page.TableDataInfo;
import com.suray.commin.core.utils.StringUtils;
import com.suray.commin.enmus.BusinessType;
import com.suray.commin.core.controller.ResponseData;
import com.suray.wcs.service.core.util.ReturnTypeBox;
import com.suray.wcs.service.init.device.DeviceManager;
import com.suray.wcs.service.pojo.HandHoist;
import com.suray.wcs.service.system.entity.NodeDB;
import com.suray.basic.wcs.plc.entity.PlcDeviceDB;
import com.suray.basic.wcs.plc.service.IPlcDeviceDBService;
import com.suray.wcs.service.system.service.impl.NodeDBServiceImpl;
import com.suray.wcs.service.websocket.DeviceInfoPush;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.*;

import static com.suray.basic.wcs.path.core.Node.parseGrid;
import static com.suray.basic.wcs.path.enums.NodeType.*;
import static com.suray.basic.wcs.plc.enums.Location.INSIDE;
import static com.suray.basic.wcs.plc.enums.PlcDeviceType.*;


/**
 * plc设备信息
 *
 * @author zhr
 */
@RestController
@RequestMapping("/plcDeviceDB")
public class PlcDeviceDBController extends BaseController {
    private Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private IPlcDeviceDBService plcDeviceDBService;
    @Autowired
    private DeviceInfoPush deviceInfoPush;
    @Autowired
    private NodeDBServiceImpl nodeDBService;

    /**
     * 获取扫码器设备
     *
     * @return
     */
    @ApiOperation("获取扫码器设备")
    @GetMapping(value = "/getScans")
    @ResponseBody
    public ResponseData getScans() {
        return ResponseData.success(
                plcDeviceDBService.queryPlcDevices(
                        new ArrayList<>(Arrays.asList(SCANNER.getTypeNum(), SCAN.getTypeNum()))));
    }

    /**
     * 获取称重设备
     *
     * @return
     */
    @ApiOperation("获取称重设备")
    @GetMapping(value = "/getWeights")
    @ResponseBody
    public ResponseData getWeights() {
        return ResponseData.success(
                plcDeviceDBService.queryPlcDevices(
                        new ArrayList<>(Arrays.asList(WEIGHT.getTypeNum(), SINGLE_WEIGHT.getTypeNum()))));
    }

    /**
     * 获取外形检测设备
     *
     * @return
     */
    @ApiOperation("获取外形检测设备")
    @GetMapping(value = "/getShapes")
    @ResponseBody
    public ResponseData getShapes() {
        return ResponseData.success(
                plcDeviceDBService.queryPlcDevices(
                        new ArrayList<>(Arrays.asList(SHAPE_DETECTION.getTypeNum(), SHAPE.getTypeNum()))));
    }

    /**
     * @param plcdeviceDB
     * @Description:根据条件查询plc设备信息
     * @author rbj
     */
    @PreAuthorize("@ss.hasPermi('plcDeviceDB:list')")
    @ApiOperation("根据条件查询plc设备信息")
    @GetMapping(value = "/getPlcdevsByPlcId")
    public TableDataInfo listDevs(PlcDeviceDB plcdeviceDB) {
        startPage();
        List<PlcDeviceDB> plcDeviceDBS = plcDeviceDBService.selectDevsByCondtion(plcdeviceDB);
        return getDataTable(plcDeviceDBS);
    }

    /**
     * @return ResponseData
     * @Description:查询Plc设备信息 输送线、提升机 <库口配置专用 添加调用小车数据>
     * @author rbj
     */
    @PostMapping(value = "/queryPlcDevs")
    @ApiOperation(value = "查询所有Plc设备信息")
    @ResponseBody
    public ResponseData queryPlcDevs() {
        return ResponseData.success(plcDeviceDBService.queryPlcDevices());
    }


    @Log(title = "plc设备信息", method = "新增Plc设备", businessType = BusinessType.INSERT)
    @PreAuthorize("@ss.hasPermi('plcDeviceDB:add')")
    @PostMapping(value = "/addPlcDevice")
    @ApiOperation(value = "新增Plc设备")
    @ResponseBody
    public ResponseData addPlcInfo(@Validated @RequestBody PlcDeviceDB plcdevicedb) {
        PlcDeviceDB systemByPlcId = plcDeviceDBService.getSystemByPlcId(plcdevicedb.getPlcId());
        if (systemByPlcId == null && plcdevicedb.getDeviceType() != SIEMENS_HOIST.getTypeNum()
                && plcdevicedb.getDeviceType() != PANASONIC_LIFT.getTypeNum()
                && plcdevicedb.getDeviceType() != TAMAGAWA_LIFTER.getTypeNum()
                && plcdevicedb.getDeviceType() != AUTOMATIC_LIFTER.getTypeNum()
                && plcdevicedb.getDeviceType() != FORK_LIFTER.getTypeNum()
                && plcdevicedb.getDeviceType() != AUTO_HOIST.getTypeNum()
                && plcdevicedb.getDeviceType() != TOOTH_HOIST.getTypeNum()
                && plcdevicedb.getDeviceType() != AUTO_TRAVERSING.getTypeNum()
                && plcdevicedb.getDeviceType() != TRANS_PLANTER.getTypeNum()
                && plcdevicedb.getDeviceType() != MONOMER_CONVEYOR.getTypeNum()
                && plcdevicedb.getDeviceType() != SHAPE_CONVEYOR.getTypeNum()
                && plcdevicedb.getDeviceType() != SHAPE.getTypeNum()
                && plcdevicedb.getDeviceType() != SCAN.getTypeNum()
                && plcdevicedb.getDeviceType() != FOLDING_MACHINE.getTypeNum()
                && plcdevicedb.getDeviceType() != SYSTEM.getTypeNum()) {
            return ResponseData.error("请先添加系统类型!");
        }
        //验证
        String checkInfo = checkPlcDevice(plcdevicedb);
        if (!"验证成功".equals(checkInfo)) {
            return ResponseData.error(checkInfo);
        }
        if (plcDeviceDBService.addPlcDevice(plcdevicedb)) {
            return ResponseData.success("新增PLC设备成功");
        } else {
            return ResponseData.error("新增PLC设备失败");
        }
    }

    @Log(title = "plc设备信息", method = "changePlcDevice", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('plcDeviceDB:edit')")
    @PostMapping(value = "/changePlcDevice")
    @ApiOperation(value = "修改Plc设备")
    @ResponseBody
    public ResponseData changePlcInfo(@Validated @RequestBody PlcDeviceDB plcdevicedb) {
        String checkInfo = checkPlcDevice(plcdevicedb);
        if (!"验证成功".equals(checkInfo)) {
            return ResponseData.error(checkInfo);
        }
        try {
            if (plcDeviceDBService.changePlc(plcdevicedb) == 1) {
                return ResponseData.success("修改成功");
            } else {
                return ResponseData.error("修改PLC设备失败");
            }
        } catch (Exception e) {
            return ResponseData.error("字段非法，重新填写");
        }
    }

    @PostMapping(value = "/checkPlcName")
    @ApiOperation(value = "Plc设备名字验证")
    @ResponseBody
    public ResponseData checkPlcName(PlcDeviceDB plcdevicedb) {
        if (plcdevicedb.getPlcId() == null || plcdevicedb.getPlcId().toString().trim().length() < 1) {
            plcdevicedb.setPlcId(-1);
        }
        if (plcDeviceDBService.checkPlcDeviceName(plcdevicedb.getDeviceName(), plcdevicedb.getPlcId())) {
            return ResponseData.error("设备名称已经存在");
        } else {
            return ResponseData.success("设备名称可用", null);
        }
    }

    @Log(title = "plc设备信息", method = "删除Plc设备", businessType = BusinessType.DELETE)
    @PreAuthorize("@ss.hasPermi('plcDeviceDB:remove')")
    @PostMapping(value = "/deletePlcDevice")
    @ApiOperation(value = "删除Plc设备")
    @ResponseBody
    public ResponseData deletePlcDeviceInfo(@RequestBody List<PlcDeviceDB> plcDeviceDBList) {
        if (plcDeviceDBList == null || plcDeviceDBList.size() < 1)
            return ResponseData.error("请先勾选需要删除项");
        List<Integer> deviceIdList = new ArrayList<Integer>();
        int delSize = deviceIdList.size();
        for (PlcDeviceDB plcdevicedb : plcDeviceDBList) {
            deviceIdList.add(plcdevicedb.getDeviceId());
        }

        List<PlcDeviceDB> noDel = plcDeviceDBService.deletePlcDevice(deviceIdList);

        if (noDel == null || noDel.size() == 0) {
            return ResponseData.success("删除成功");
        } else if (noDel.size() > 1 && noDel.size() < delSize) {
            StringBuilder plcNameTemp = new StringBuilder();
            for (PlcDeviceDB plcdevicedb : noDel) {
                plcNameTemp.append(plcdevicedb.getDeviceName() + ",");
            }
            plcNameTemp.deleteCharAt(plcNameTemp.length() - 1);
            return ResponseData.success("部分删除成功," + noDel.size() + "数据未删掉。未删除的plc设备名称为" + plcNameTemp);
        } else {
            return ResponseData.error("删除失败");
        }
    }

    /**
     * 删除Plc设备
     */
    @PreAuthorize("@ss.hasPermi('plcDeviceDB:remove')")
    @Log(title = "plc设备信息", method = "删除Plc设备", businessType = BusinessType.DELETE)
    @ApiOperation("删除Plc设备")
    @DeleteMapping("/{deviceId}")
    public ResponseData remove(@PathVariable Long[] deviceId) {
        return toAjax(plcDeviceDBService.deletePlcDevByIds(deviceId));
    }

    @PostMapping("/getDeviceTypeName")
    @ApiOperation("获取设备类型下拉框")
    @ResponseBody
    public ResponseData getDeviceTypeName() {
        return ResponseData.success(ReturnTypeBox.returnTypeBox(PlcDeviceType.class));
    }

    @PostMapping("/getLocationName")
    @ApiOperation("获取提升机位置下拉框")
    @ResponseBody
    public ResponseData getLocationName() {
        return ResponseData.success(ReturnTypeBox.returnTypeBox(Location.class));
    }

    /**
     * 获取在当前层小车的状态
     */
    @GetMapping(value = "/getHoistInfo")
    @ResponseBody
    @ApiOperation(value = "获取在当前层小车的状态")
    public ResponseData getHoistInfo() {
        Map<String, List<HandHoist>> map = new HashMap<>();
        map.put("hoistInfo", deviceInfoPush.getHandHoists());
        return ResponseData.success("查询成功", map);
    }


    /**
     * 检验plc设备
     *
     * @return
     */
    public String checkPlcDevice(PlcDeviceDB plcdevicedb) {
        if (plcDeviceDBService.checkPlcDeviceNo(plcdevicedb)) {
            return "设备编号不可重复";
        }
        if (plcDeviceDBService.checkPlcDeviceName(plcdevicedb)) {
            return "设备名称不可重复";
        }
        if (plcDeviceDBService.checkPlcDeviceName(plcdevicedb.getDeviceName(), plcdevicedb.getPlcId()))
        //提升机
        if (plcdevicedb.getDeviceType() == PANASONIC_LIFT.getTypeNum()
                || plcdevicedb.getDeviceType() == SIEMENS_HOIST.getTypeNum() || plcdevicedb.getDeviceType() == TAMAGAWA_LIFTER.getTypeNum()) {
            if (plcdevicedb.getLocation() == null) {
                return "提升机相对位置填写不完全";
            }
            //if 提升机中->检测锁定位置是否和提升机位置一致
            if (plcdevicedb.getLocation() == INSIDE.getCode()) {
                if (!plcdevicedb.getDeviceLocation().equals(plcdevicedb.getPlcLockLocation())) {
                    return "锁定位置与提升机位置不一致";
                }
            }
            //验证锁定位置是否为提升机类型
            Node node = parseGrid(plcdevicedb.getPlcLockLocation());
            NodeDB nodedb = nodeDBService.getNodeDB(node);
            if (nodedb == null) {
                return "没查询到该结点";
            }
            if (nodedb.getGridType() != L) {
                return "锁定位置不是提升机类型";
            }
        }
        //工位
        if (plcdevicedb.getDeviceType() == CHAIN_STATION.getTypeNum()) {
            if (!plcdevicedb.getDeviceLocation().equals(plcdevicedb.getPlcLockLocation())) {
                return "锁定位置与工位位置不一致";
            }
            //验证锁定位置是否为工位类型
            Node node = parseGrid(plcdevicedb.getPlcLockLocation());
            NodeDB nodedb = nodeDBService.getNodeDB(node);
            if (nodedb == null) {
                return "没查询到该结点";
            }
            if (nodedb.getGridType() != ST && nodedb.getGridType() != CONNECTION) {
                return "锁定位置不是工位类型";
            }
        }
        return "验证成功";
    }

    @PreAuthorize("@ss.hasPermi('plcDeviceDB:sendDataSuc')")
    @Log(title = "plc设备信息", method = "发送数据合格", businessType = BusinessType.UPDATE)
    @ApiOperation("发送数据合格")
    @PostMapping(value = "/sendDataSuc")
    @ResponseBody
    public ResponseData sendDatSuccess(@RequestBody String deviceName) {
        log.info("接收到给工位：" + deviceName + "发送数据合格的指令");
        try {
            StationOper stationOper = (StationOper) Plc.deviceBaseNameMap.get(deviceName);
            if (stationOper == null) {
                return ResponseData.error(deviceName + ":不在线！");
            }
            PlcOperImpl plcOper = PlcOperImpl.getPlcOper(stationOper.getPlc());
            plcOper.dataEligible(stationOper.getDeviceNo(), true);
            return ResponseData.success("发送成功");
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseData.error("发送失败");
        }
    }

    /**
     * 根据plc编号获取详细信息
     */
    @ApiOperation("根据plc编号获取详细信息")
    @GetMapping(value = "/getPlcDev/{deviceId}")
    public ResponseData getPlcDev(@PathVariable Long deviceId) {
        return ResponseData.success(plcDeviceDBService.selectPlcDevById(deviceId));
    }
    /**
     * 扫码开启
     *
     * @param deviceNo
     * @return
     */
    @PreAuthorize("@ss.hasPermi('plcDeviceDB:openScannerBar')")
    @Log(title = "plc设备信息", method = "打开扫码器", businessType = BusinessType.UPDATE)
    @ApiOperation("打开扫码器")
    @PostMapping(value = "/openScannerBar")
    @ResponseBody
    public ResponseData openScanner(@RequestBody String deviceNo) {
        if (StringUtils.isEmpty(deviceNo)) {
            return ResponseData.error("编号不能为空");
        }
        Scanner scanner= DeviceManager.getByScanNo(deviceNo);
        if ( scanner == null) {
            return ResponseData.error("编号为" + deviceNo + "的设备不存在，请确认后重试");
        }
        try {
            scanner.startScan();
        } catch (IOException e) {
            return ResponseData.error("打开扫码器失败！");
        }
        return ResponseData.success("打开扫码器成功");
    }

    /**
     * 扫码关闭
     *
     * @param deviceNo
     * @return
     */
    @PreAuthorize("@ss.hasPermi('plcDeviceDB:closeScannerBar')")
    @Log(title = "plc设备手动操作", method = "关闭扫码器", businessType = BusinessType.UPDATE)
    @ApiOperation("关闭扫码器")
    @PostMapping("/closeScannerBar")
    @ResponseBody
    public ResponseData closeScanner(@RequestBody String deviceNo) {
        if (StringUtils.isEmpty(deviceNo)) {
            return ResponseData.error("编号不能为空");
        }
        Scanner scanner= DeviceManager.getByScanNo(deviceNo);
        if (scanner == null) {
            return ResponseData.error("编号为" + deviceNo + "的设备不存在，请确认后重试");
        }
        try {
            scanner.stopScan();
        } catch (IOException e) {
            return ResponseData.error("关闭扫码器失败！");
        }
        return ResponseData.success("关闭扫码器成功");
    }
}
